#define _GNU_SOURCE
#include "app_device.h"
#include "log/log.h"
#include "app_message.h"
#include "app_common.h"
#include "app_mqtt.h"
#include "app_buffer.h"
#include "app_pool.h"
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "string.h"
#include "fcntl.h" // file control

static Device *device;
/// @brief 发送消息到远程的任务函数 由线程池中的某个分线程执行
/// @param arg
/// @return
static int send_task_func(void *arg)
{
    Device *device = (Device *)arg;

    // 从上行缓冲区读取到一个字符数组消息
    char chars_buf[128];

    int len = app_buffer_read(device->up_buffer, chars_buf, sizeof(chars_buf));
    if (len == -1)
    {
        log_error("读取上行缓冲区失败");
        return -1;
    }

    // 将字符数组转换成json格式
    char *json = app_message_charsToJson(chars_buf, len);
    // 发送消息到远程
    app_mqtt_send(json);

    return 0;
}
static int write_task_func(void *arg)
{
    // 从下行缓冲区读取到一个字符数组消息
    char chars_buf[128] = {0};
    int len = app_buffer_read(device->down_buffer, chars_buf, sizeof(chars_buf));
    if (len == -1)
    {
        log_error("读取下行缓冲区失败");
        return -1;
    }
    if (len > 0 && device->pre_write)
    {
        len = device->pre_write(chars_buf, len);
        if (len == -1)
        {
            log_error("设备数据写前处理失败");
            return -1;
        }
        if (len > 0)
        {
            // 如果距离上次写入时间间隔小于200ms，则等待不够的时间
            long distance_time = app_common_getCurrentTime() - device->last_write_time;
            if (distance_time < 200)
            {
                usleep((200 - distance_time) * 1000);
            }

            ssize_t write_len = write(device->fd, chars_buf, len);
            if (write_len != len)
            {
                log_error("写入设备文件失败");
                return -1;
            }
            // fsync(device->fd);

            log_debug("写入设备文件成功 : %.*s", len, chars_buf);
            device->last_write_time = app_common_getCurrentTime();
            return 0;
        }
    }

    return -1;
}

static int receive_msg_callback(char *json)
{
    char chars_buf[128] = {0};
    int len = app_message_jsonToChars(json, chars_buf, sizeof(chars_buf));

    if (len == -1)
    {
        log_error("将json转换为字符数组失败");
        return -1;
    }
    // 写入下行缓冲区
    int result = app_buffer_write(device->down_buffer, chars_buf, len);
    if (result == -1)
    {
        log_error("写入下行缓冲区失败");
        return -1;
    }
    // 将写入消息的操作交给线程池来执行
    app_pool_registerTask(write_task_func, NULL); //?
    return 0;
}

Device *app_device_init(char *file_name)
{
    // 初始化设备内存
    device = (Device *)malloc(sizeof(Device));
    device->flie_name = file_name;
    device->fd = open(file_name, O_RDWR); // 文件已经在目录中创建好
    device->up_buffer = app_buffer_init(1024);
    device->down_buffer = app_buffer_init(1024);
    device->is_read_thread_running = 0; // 0:停止 1:运行
    device->last_write_time = 0;
    device->post_read = NULL;
    device->pre_write = NULL;
    return device;
}

/// @brief 不断读取下游设备发送来的数据的线程函数
/// @param arg
/// @return /
static void *read_thread_func(void *arg)
{
    while (device->is_read_thread_running)
    {
        char read_buf[128];
        ssize_t len = read(device->fd, read_buf, sizeof(read_buf));
        if (len == -1)
        {
            log_error("读取设备文件失败");
            return NULL;
        }
        // 对读取到的蓝牙数据进行读后处理，转换为字符数组
        if (len > 0 && device->post_read)
        {
            len = device->post_read(read_buf, len);
            // 如果处理失败，结束
            if (len == -1)
            {
                log_error("设备数据读后处理失败");
                return NULL;
            }
            if (len > 0)
            {
                log_debug("读取到数据 %.*s", len, read_buf);
                // 将处理后的数据写入到上行缓冲区
                app_buffer_write(device->up_buffer, read_buf, len);
                // 将发送消息的操作交给线程池来执行
                app_pool_registerTask(send_task_func, device);
            }
        }
    }
    return NULL;
}
int app_device_start()
{
    if (device->is_read_thread_running == 1)
    {
        log_debug("设备读线程已经启动");
        return 0;
    }
    // 创建启动读数据线程
    device->is_read_thread_running = 1;
    pthread_create(&device->read_thread, NULL, read_thread_func, NULL);
    // 下行
    //  注册接收远程消息的回调函数
    app_mqtt_registerRecvCallback(receive_msg_callback);
    return 0;
}

void app_device_free()
{
}
